/*-------------------------------------------------------------------------
 *
 * atomics.h
 *	  原子操作。
 *
 * 依赖于硬件和编译器的函数，用于以原子方式操纵内存并处理缓存一致性。
 * 用于实现锁定设施和无锁算法/数据结构。
 *
 * 为了在某个平台/编译器上启动 postgres，至少应该提供以下操作的实现：
 * * pg_compiler_barrier(), pg_write_barrier(), pg_read_barrier()
 * * pg_atomic_compare_exchange_u32(), pg_atomic_fetch_add_u32()
 * * pg_atomic_test_set_flag(), pg_atomic_init_flag(), pg_atomic_clear_flag()
 * * 如果适用，应该定义 PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY。
 *
 * 存在几种编译器的通用、硬件无关的实现，这可能是足够的，尽管可能不是最佳的，
 * 对于一个新平台。如果没有这样的通用实现，将使用自旋锁（甚至操作系统提供的信号量）
 * 来实现 API。
 *
 * 仅在您的平台可以有效（并且显然正确）地使用它们时实现 _u64 原子操作。
 *
 * 尽可能使用更高层次的功能（lwlocks、spinlocks、heavyweight locks）。
 * 使用这些设施编写正确代码是困难的。
 *
 * 要了解在 PostgreSQL 后端中使用内存屏障，请参见 src/backend/storage/lmgr/README.barrier
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/port/atomics.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef ATOMICS_H
#define ATOMICS_H

#ifdef FRONTEND
#error "atomics.h may not be included from frontend code"
#endif

#define INSIDE_ATOMICS_H

#include <limits.h>

/*
 * 首先包含一组特定于架构的文件。
 *
 * 这些文件可以提供完整的原子集合，或者如果这些平台上常用的编译器提供可用的通用代码，则几乎什么也不做。
 *
 * 如果您的平台的所有常见实现提供内置函数，请不要添加实际原子操作的内联汇编。内置函数更容易理解，并且可能更好地支持更多架构。
 *
 * 在这里定义内存屏障语义通常是有意义的，因为例如，x86内存屏障的通用编译器内置函数不能知道postgres不需要x86读/写屏障做任何其他事情，只需一个编译器屏障。
 *
 */
#if defined(__arm__) || defined(__arm) || \
	defined(__aarch64__) || defined(__aarch64)
#include "port/atomics/arch-arm.h"
#elif defined(__i386__) || defined(__i386) || defined(__x86_64__)
#include "port/atomics/arch-x86.h"
#elif defined(__ia64__) || defined(__ia64)
#include "port/atomics/arch-ia64.h"
#elif defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__)
#include "port/atomics/arch-ppc.h"
#elif defined(__hppa) || defined(__hppa__)
#include "port/atomics/arch-hppa.h"
#endif

/*
 * 编译器特定，但与架构无关的实现。
 *
 * 提供原子设施的架构无关实现。至少应该提供编译器屏障，但使用编译器内置函数的完整实现
 * * pg_compiler_barrier()、pg_write_barrier()、pg_read_barrier()
 * * pg_atomic_compare_exchange_u32()、pg_atomic_fetch_add_u32()
 * 是个好主意。
 */
/*
 * gcc或兼容，包括clang和icc。排除xlc。ppc64le的 "IBM XL C/C++ for Linux, V13.1.2" 模拟gcc，但__sync_lock_test_and_set()
 * 的一个字节类型会引发SIGSEGV。该bug在V13.1.5（2016-12）时解决。
 */
#if (defined(__GNUC__) || defined(__INTEL_COMPILER)) && !(defined(__IBMC__) || defined(__IBMCPP__))
#include "port/atomics/generic-gcc.h"
#elif defined(_MSC_VER)
#include "port/atomics/generic-msvc.h"
#elif defined(__hpux) && defined(__ia64) && !defined(__GNUC__)
#include "port/atomics/generic-acc.h"
#elif defined(__SUNPRO_C) && !defined(__GNUC__)
#include "port/atomics/generic-sunpro.h"
#else
/*
 * 不支持的编译器，我们可能使用较慢的后备方案……至少应该提供编译器屏障。
 */
#endif

/*
 * 为没有足够自旋锁和/或原子支持的平台提供pg_*_barrier()、pg_atomic**_flag和pg_atomic_* API的完整后备。
 * 在自旋锁支持的原子情况下，预期模拟是高效的，尽管不如本地原子支持。
 */
#include "port/atomics/fallback.h"

/*
 * 使用受支持的基础设施提供额外操作。如果基础的原子操作是高效的，预计这些操作也将是高效的。
 */
#include "port/atomics/generic.h"


/*
 * pg_compiler_barrier - 防止编译器移动代码
 *
 * 编译器屏障不需（且最好不）发出任何实际机器代码，但必须充当优化边界：编译器不得重新排序屏障周围的主存加载或存储操作。
 * 但是，CPU仍然可以在运行时重新排序加载或存储，如果体系结构的内存模型允许这样做。
 */
#define pg_compiler_barrier()	pg_compiler_barrier_impl()


/*
 * pg_memory_barrier - 防止CPU重新排序内存访问
 *
 * 内存屏障必须作为编译器屏障，并且必须确保屏障之前发出的所有加载和存储在屏障之后的任何加载或存储之前完成。除非加载和存储是完全排序的（在大多数架构上不是这种情况），这需要发出某种类型的内存屏障指令。
 */
#define pg_memory_barrier() pg_memory_barrier_impl()

/*
 * pg_(read|write)_barrier - 防止CPU重新排序内存访问
 *
 * 读屏障必须作为编译器屏障，并且还必须确保在屏障之前发出的任何加载在屏障之后发出的任何加载之前完成。类似地，写屏障作为编译器屏障，并且也对存储进行排序。因此，读和写屏障比完整内存屏障弱，但比编译器屏障强。在实际操作中，在具有强内存顺序的机器上，读和写屏障可能只需要编译器屏障。
 */
#define pg_read_barrier()	pg_read_barrier_impl()
#define pg_write_barrier()	pg_write_barrier_impl()

/*
 * Spinloop delay - 允许CPU在忙碌的循环中放松
 */
#define pg_spin_delay() pg_spin_delay_impl()

/*
 * pg_atomic_init_flag - 初始化原子标志。
 *
 * 无屏障语义。
 */
static inline void
pg_atomic_init_flag(volatile pg_atomic_flag *ptr)
{
	pg_atomic_init_flag_impl(ptr);
}

/*
 * pg_atomic_test_set_flag - TAS()
 *
 * 如果标志成功设置，则返回true，否则返回false。
 *
 * 获取（包括读屏障）语义。
 */
static inline bool
pg_atomic_test_set_flag(volatile pg_atomic_flag *ptr)
{
	return pg_atomic_test_set_flag_impl(ptr);
}

/*
 * pg_atomic_unlocked_test_flag - 检查锁是否为空闲
 *
 * 如果标志当前未设置则返回true，否则返回false。
 *
 * 无屏障语义。
 */
static inline bool
pg_atomic_unlocked_test_flag(volatile pg_atomic_flag *ptr)
{
	return pg_atomic_unlocked_test_flag_impl(ptr);
}

/*
 * pg_atomic_clear_flag - 释放由TAS()设置的锁
 *
 * 释放（包括写屏障）语义。
 */
static inline void
pg_atomic_clear_flag(volatile pg_atomic_flag *ptr)
{
	pg_atomic_clear_flag_impl(ptr);
}


/*
 * pg_atomic_init_u32 - 初始化原子变量
 *
 * 必须在任何并发使用之前完成..
 *
 * 无屏障语义。
 */
static inline void
pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
{
	AssertPointerAlignment(ptr, 4);

	pg_atomic_init_u32_impl(ptr, val);
}

/*
 * pg_atomic_read_u32 - 从原子变量中进行无锁读操作。
 *
 * 此读操作保证返回一个值，因为该值在过去的某个时刻由此或另一个进程写入。然而，没有缓存一致性交互来保证该值自那时以来没有再次被写入。
 *
 * 无屏障语义。
 */
static inline uint32
pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
{
	AssertPointerAlignment(ptr, 4);
	return pg_atomic_read_u32_impl(ptr);
}

/*
 * pg_atomic_write_u32 - 写入原子变量。
 *
 * 该写入保证整体成功，即对于任何读取者，无法观察到部分写入。请注意，这与pg_atomic_compare_exchange_u32正确交互，而与pg_atomic_unlocked_write_u32()相对。
 *
 * 无屏障语义。
 */
static inline void
pg_atomic_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
{
	AssertPointerAlignment(ptr, 4);

	pg_atomic_write_u32_impl(ptr, val);
}

/*
 * pg_atomic_unlocked_write_u32 - 无锁写入原子变量。
 *
 * 该写入保证整体成功，即对于任何读取者，无法观察到部分写入。但请注意，以这种方式写入不保证与像pg_atomic_compare_exchange_u32这样的读-修改-写操作正确交互。此方法仅应在因原子模拟引起的小幅性能下降不可接受的情况下使用。
 *
 * 无屏障语义。
 */
static inline void
pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
{
	AssertPointerAlignment(ptr, 4);

	pg_atomic_unlocked_write_u32_impl(ptr, val);
}

/*
 * pg_atomic_exchange_u32 - 交换新值与当前值
 *
 * 返回交换前'ptr'的旧值。
 *
 * 完全屏障语义。
 */
static inline uint32
pg_atomic_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 newval)
{
	AssertPointerAlignment(ptr, 4);

	return pg_atomic_exchange_u32_impl(ptr, newval);
}

/*
 * pg_atomic_compare_exchange_u32 - CAS 操作
 *
 * 原子地将ptr的当前值与*expected进行比较，并在ptr和*expected具有相同值时存储新值。*ptr的当前值将始终存储在*expected中。
 *
 * 如果值已交换，返回true，否则返回false。
 *
 * 完全屏障语义。
 */
static inline bool
pg_atomic_compare_exchange_u32(volatile pg_atomic_uint32 *ptr,
							   uint32 *expected, uint32 newval)
{
	AssertPointerAlignment(ptr, 4);
	AssertPointerAlignment(expected, 4);

	return pg_atomic_compare_exchange_u32_impl(ptr, expected, newval);
}

/*
 * pg_atomic_fetch_add_u32 - 原子地对变量进行加法
 *
 * 返回算术操作之前ptr的值。
 *
 * 完全屏障语义。
 */
static inline uint32
pg_atomic_fetch_add_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
{
	AssertPointerAlignment(ptr, 4);
	return pg_atomic_fetch_add_u32_impl(ptr, add_);
}

/*
 * pg_atomic_fetch_sub_u32 - 原子地从变量中进行减法
 *
 * 返回算术操作之前ptr的值。注意，sub_可能由于平台限制而不是INT_MIN。
 *
 * 完全屏障语义。
 */
static inline uint32
pg_atomic_fetch_sub_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
{
	AssertPointerAlignment(ptr, 4);
	Assert(sub_ != INT_MIN);
	return pg_atomic_fetch_sub_u32_impl(ptr, sub_);
}

/*
 * pg_atomic_fetch_and_u32 - 原子地与变量进行位与操作
 *
 * 返回在算术操作前的ptr值。
 *
 * 完全屏障语义。
 */
static inline uint32
pg_atomic_fetch_and_u32(volatile pg_atomic_uint32 *ptr, uint32 and_)
{
	AssertPointerAlignment(ptr, 4);
	return pg_atomic_fetch_and_u32_impl(ptr, and_);
}

/*
 * pg_atomic_fetch_or_u32 - 原子地与变量进行位或操作
 *
 * 返回在算术操作前的ptr值。
 *
 * 完全屏障语义。
 */
static inline uint32
pg_atomic_fetch_or_u32(volatile pg_atomic_uint32 *ptr, uint32 or_)
{
	AssertPointerAlignment(ptr, 4);
	return pg_atomic_fetch_or_u32_impl(ptr, or_);
}

/*
 * pg_atomic_add_fetch_u32 - 原子地向变量添加
 *
 * 返回在算术操作后的ptr值。
 *
 * 完全屏障语义。
 */
static inline uint32
pg_atomic_add_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
{
	AssertPointerAlignment(ptr, 4);
	return pg_atomic_add_fetch_u32_impl(ptr, add_);
}

/*
 * pg_atomic_sub_fetch_u32 - 原子地从变量中减去
 *
 * 返回在算术操作后的ptr值。请注意，由于平台限制，sub_可能
 * 不是INT_MIN。
 *
 * 完全屏障语义。
 */
static inline uint32
pg_atomic_sub_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
{
	AssertPointerAlignment(ptr, 4);
	Assert(sub_ != INT_MIN);
	return pg_atomic_sub_fetch_u32_impl(ptr, sub_);
}

/* ----
 * 64位操作与其32位对应物具有相同的语义
 * 如果它们可用。请检查相应的32位函数以获取
 * 文档。
 * ----
 */
static inline void
pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
{
	/*
	 * 在使用基于自旋锁的回退实现时，不能强制对齐 - 并且不需要
	 * 它 - 因此仅在不使用时进行断言。
	 */
#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
	AssertPointerAlignment(ptr, 8);
#endif
	pg_atomic_init_u64_impl(ptr, val);
}

static inline uint64
pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
{
#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
	AssertPointerAlignment(ptr, 8);
#endif
	return pg_atomic_read_u64_impl(ptr);
}

static inline void
pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
{
#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
	AssertPointerAlignment(ptr, 8);
#endif
	pg_atomic_write_u64_impl(ptr, val);
}

static inline uint64
pg_atomic_exchange_u64(volatile pg_atomic_uint64 *ptr, uint64 newval)
{
#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
	AssertPointerAlignment(ptr, 8);
#endif
	return pg_atomic_exchange_u64_impl(ptr, newval);
}

static inline bool
pg_atomic_compare_exchange_u64(volatile pg_atomic_uint64 *ptr,
							   uint64 *expected, uint64 newval)
{
#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
	AssertPointerAlignment(ptr, 8);
	AssertPointerAlignment(expected, 8);
#endif
	return pg_atomic_compare_exchange_u64_impl(ptr, expected, newval);
}

static inline uint64
pg_atomic_fetch_add_u64(volatile pg_atomic_uint64 *ptr, int64 add_)
{
#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
	AssertPointerAlignment(ptr, 8);
#endif
	return pg_atomic_fetch_add_u64_impl(ptr, add_);
}

static inline uint64
pg_atomic_fetch_sub_u64(volatile pg_atomic_uint64 *ptr, int64 sub_)
{
#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
	AssertPointerAlignment(ptr, 8);
#endif
	Assert(sub_ != PG_INT64_MIN);
	return pg_atomic_fetch_sub_u64_impl(ptr, sub_);
}

static inline uint64
pg_atomic_fetch_and_u64(volatile pg_atomic_uint64 *ptr, uint64 and_)
{
#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
	AssertPointerAlignment(ptr, 8);
#endif
	return pg_atomic_fetch_and_u64_impl(ptr, and_);
}

static inline uint64
pg_atomic_fetch_or_u64(volatile pg_atomic_uint64 *ptr, uint64 or_)
{
#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
	AssertPointerAlignment(ptr, 8);
#endif
	return pg_atomic_fetch_or_u64_impl(ptr, or_);
}

static inline uint64
pg_atomic_add_fetch_u64(volatile pg_atomic_uint64 *ptr, int64 add_)
{
#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
	AssertPointerAlignment(ptr, 8);
#endif
	return pg_atomic_add_fetch_u64_impl(ptr, add_);
}

static inline uint64
pg_atomic_sub_fetch_u64(volatile pg_atomic_uint64 *ptr, int64 sub_)
{
#ifndef PG_HAVE_ATOMIC_U64_SIMULATION
	AssertPointerAlignment(ptr, 8);
#endif
	Assert(sub_ != PG_INT64_MIN);
	return pg_atomic_sub_fetch_u64_impl(ptr, sub_);
}

#undef INSIDE_ATOMICS_H

#endif							/* ATOMICS_H */
